package com.kusen.lock8;

import java.util.concurrent.TimeUnit;

/**
 * 演示8锁问题
 * 多线程操作 高内聚，低耦合。线程操作资源类
 * 总结：8锁问题，如果俩个方法都加了synchronized。那么这个就会按照调用的方式来调用
 * 如果是一个是普通的锁，一个是静态方法的锁，那么这两个是安装时间的方式来掉用。因为是两个不同的对象在调用
 * 如果是一个加锁一个是普通方法，相互不存在资源调度的问题，按照先后调度来
 * 如果是两个对象调用，都是synchronized。那么是两个不同的对象调用，所以不会产生资源调度问题
 */
public class LockDemo1 {
    public static void main(String[] args) throws InterruptedException {
        //dome01();
        // dome02();
        //dome03();
        //dome04();
        //dome05();
        //dome06();
        //dome07();
        dome08();

    }

    /**
     * 场景八
     * 一个被static+synchronized 修饰的方法和普通的synchronized方法，先执行sendEmail()还是sendMsm()？
     * 答案：sendMsm
     * 解释：因为一个是锁的是class对象，一个是锁的是调用者。所以是两个不同的锁，两者互不干涉。
     *
     * @throws InterruptedException
     */
    private static void dome08() throws InterruptedException {
        //创建资源类
        Phone8 phoneA = new Phone8();
        Phone8 phoneB = new Phone8();
        //创建线程
        new Thread(() -> {
            phoneA.sendEmail();
        }, "A").start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(() -> {
            phoneB.sendMsm();
        }, "B").start();
    }

    /**
     * 场景七(全局锁)
     * 同被static+synchronized 修饰的两个方法，是先sendEmail()还是callPhone()?
     * 答案：sendEmail
     * 解释：只要方法被 static 修饰，锁的对象就是 Class模板对象,这个则全局唯一
     * 所以说这里是同一个锁，并不是因为synchronized
     *
     * @throws InterruptedException
     */
    private static void dome07() throws InterruptedException {
        //创建资源类
        Phone7 phoneA = new Phone7();
        Phone7 phoneB = new Phone7();
        //创建线程
        new Thread(() -> {
            phoneA.sendEmail();
        }, "A").start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(() -> {
            phoneB.sendMsm();
        }, "B").start();
    }

    /**
     * 场景六
     * 被synchronized 修饰的普通方法和静态方法  是先sendEmail() 还是 sendMsm()?
     * 答案：sendMsm
     * 解释：只要被static修饰锁的是class唯一模板，而synchronized 锁的是调用的对象
     * 这里是两个锁互不影响，按时间先后执行
     *
     * @throws InterruptedException
     */
    private static void dome06() throws InterruptedException {
        //创建资源类
        Phone6 phone6 = new Phone6();
        //创建线程
        new Thread(() -> {
            phone6.sendEmail();
        }, "A").start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(() -> {
            phone6.sendMsm();
        }).start();
    }

    /**
     * 场景五(全局锁和局部锁的概念)
     * 两个静态同步方法 都被synchronized 修饰 是先sendEmail() 还是sendMsm()?
     * 答案：sendEmial
     * 解释：只要方法被 static 修饰，锁的对象就是 Class模板对象,这个则全局唯一！
     * 所以说这里是同一个锁，并不是因为synchronized  这里程序会从上往下依次执行
     *
     * @throws InterruptedException
     */
    private static void dome05() throws InterruptedException {
        //创建资源类
        Phone5 phone5 = new Phone5();
        //创建线程
        new Thread(() -> {
            phone5.sendEmail();
        }, "A").start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(() -> {
            phone5.sendMsm();
        }).start();
    }

    /**
     * 场景4
     * 被synchronized 修饰的不同方法 先执行sendEmail() 还是sendMsm()？
     * 答案：还是sendMsm
     * 解释：被synchronized 修饰的不同方法 锁的对象是调用者
     * 这里锁的是两个不同的调用者，所有互不影响
     *
     * @throws InterruptedException
     */
    private static void dome04() throws InterruptedException {
        //创建资源类
        Phone4 phoneA = new Phone4();
        Phone4 phoneB = new Phone4();
        //创建线程
        new Thread(() -> {
            phoneA.sendEmail();
        }, "A").start();
        TimeUnit.SECONDS.sleep(3);
        new Thread(() -> {
            phoneB.sendMsm();
        }, "B").start();
    }

    /**
     * 场景3
     * 被synchronized 修饰的方式和普通方法 先执行sendEmail() 还是 sendMsm()
     * 答案：sendMsm()
     * 解释：没有加锁的这个普通方法不是同步方法，不受锁的影响
     *
     * @throws InterruptedException
     */
    private static void dome03() throws InterruptedException {
        //创建资源类
        Phone3 phone3 = new Phone3();
        //创建线程
        new Thread(() -> {
            phone3.sendEmail();
        }, "A").start();
        TimeUnit.SECONDS.sleep(3);
        new Thread(() -> {
            phone3.sendMsm();
        }, "B").start();
    }

    /**
     * 场景二
     * 在资源类的 sendEmail()休眠三秒后  是先执行sendEmail() 还是 sendMsm()
     * 答案：sendEmail
     * 解释：被 synchronized 修饰的方式，锁的对象是方法的调用者
     * 所以说这里两个方法调用的对象是同一个，先调用的先执行！
     *
     * @throws InterruptedException
     */
    private static void dome02() throws InterruptedException {
        //创建资源类
        Phone2 phone2 = new Phone2();
        //创建线程
        new Thread(() -> {
            phone2.sendEmail();
        }, "A").start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(() -> {
            phone2.sendMsm();
        }).start();
    }

    /**
     * 场景一
     * 标准情况下 是先sendEmail()　还是先callPhone()?
     * 答案：sendEmail
     * 解释：被 synchronized 修饰的方式，锁的对象是方法的调用者
     * 所以说这里两个方法调用的对象是同一个，先调用的先执行！
     */
    private static void Dome01() throws InterruptedException {
        //创建资源类
        Phone1 phone1 = new Phone1();
        //创建线程
        new Thread(() -> {
            phone1.sendMsm();
        }, "B").start();
        //程序等待3秒时间
        TimeUnit.SECONDS.sleep(3);
        new Thread(() -> {
            phone1.sendEmail();
        }, "A").start();
    }
}

/**
 * 资源类
 */
class Phone1 {
    //发送邮件的方法
    public synchronized void sendEmail() {
        System.out.println("sendEmail");
    }

    //发送短信的方法
    public synchronized void sendMsm() {
        System.out.println("sendMsm");
    }
}

/**
 * 资源类
 */
class Phone2 {
    //发送邮件的方法
    public synchronized void sendEmail() {
        try {
            //在资源类里面添加一个时间等待的操作
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    //发送短信的方法
    public synchronized void sendMsm() {
        System.out.println("sendMsm");
    }
}

/**
 * 资源类
 */
class Phone3 {
    //发送邮件的方法
    public synchronized void sendEmail() {
        try {
            //在资源类里面添加一个时间等待的操作
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    //没有加 synchronized 和 static 的方法就是一个普通的方法
    public void sendMsm() {
        System.out.println("sendMsm");
    }
}

/**
 * 资源类
 */
class Phone4 {
    //发送邮件的方法
    public synchronized void sendEmail() {
        try {
            //在资源类里面添加一个时间等待的操作
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    //没有加 synchronized 和 static 的方法就是一个普通的方法
    public synchronized void sendMsm() {
        System.out.println("sendMsm");
    }
}

/**
 * 资源类
 */
class Phone5 {
    //发送邮件的方法
    public static synchronized void sendEmail() {
        try {
            //在资源类里面添加一个时间等待的操作
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    //发短信的方法 被static修饰的
    public static synchronized void sendMsm() {
        System.out.println("sendMsm");
    }
}

/**
 * 资源类
 */
class Phone6 {
    //发送邮件的方法
    public static synchronized void sendEmail() {
        try {
            //在资源类里面添加一个时间等待的操作 被static修饰
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    //发短信的方法
    public synchronized void sendMsm() {
        System.out.println("sendMsm");
    }
}

/**
 * 资源类
 */
class Phone7 {
    //发送邮件的方法
    public static synchronized void sendEmail() {
        try {
            //在资源类里面添加一个时间等待的操作 被static修饰
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    //发短信的方法 被static修饰
    public static synchronized void sendMsm() {
        System.out.println("sendMsm");
    }
}

/**
 * 资源类
 */
class Phone8 {
    //发送邮件的方法
    public static synchronized void sendEmail() {
        try {
            //在资源类里面添加一个时间等待的操作 被static修饰
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sendEmail");
    }

    //发短信的方法
    public synchronized void sendMsm() {
        System.out.println("sendMsm");
    }
}